﻿#region File Description
/****************************************************************************
*                                                                           *
* Game Manager.                                                             *
*                                                                           *
* Copyright (c) Ionescu Marius. All rights reserved(2013).                  *
*                                                                           *
****************************************************************************/
#endregion
namespace Silverlight3D
{
    using System.Windows;
    using System.Windows.Media.Media3D;

    /// <summary>
    /// Deals with the non-affine transform required to stretch a UIElement (e.g. an image) between four screen coordinates.
    /// </summary>
    /// <remarks>Thanks to <![CDATA[http://www.charlespetzold.com/blog/2007/08/250638.html]]></remarks>
    public class Matrix3DTransformer
    {
        /// <summary>
        /// The Matrix3D returned by this method is such that it can map a rectangular piece of content (e.g. an image) so that it stretches between
        /// four 2D points.  e.g. given 4 2D points corresponding to the corners of a die face, which may have been foreshortened by the 3D perspective,
        /// rotated, scaled or whatever, the Matrix3D object returned can be put in an Image's Projection property, then the image will map onto the side of the die.
        /// </summary>
        public Matrix3D CalculateNewTransform(Size size, Point ptUL, Point ptUR, Point ptLL, Point ptLR)
        {
            // Scale transform
            Matrix3D S = new Matrix3D();
            S.M11 = 1 / size.Width;
            S.M22 = 1 / size.Height;

            // See http://www.charlespetzold.com/blog/2007/08/250638.html for math that follows

            // Affine transform
            Matrix3D A = new Matrix3D();
            A.OffsetX = ptUL.X;
            A.OffsetY = ptUL.Y;
            A.M11 = (ptUR.X - A.OffsetX) / 1;
            A.M12 = (ptUR.Y - A.OffsetY) / 1;
            A.M21 = (ptLL.X - A.OffsetX) / 1;
            A.M22 = (ptLL.Y - A.OffsetY) / 1;

            // Non-Affine transform
            Matrix3D B = new Matrix3D();
            double den = A.M11 * A.M22 - A.M12 * A.M21;
            double a = (A.M22 * ptLR.X - A.M21 * ptLR.Y + A.M21 * A.OffsetY - A.M22 * A.OffsetX) / den;
            double b = (A.M11 * ptLR.Y - A.M12 * ptLR.X + A.M12 * A.OffsetX - A.M11 * A.OffsetY) / den;

            B.M11 = a / (a + b - 1);
            B.M22 = b / (a + b - 1);
            B.M14 = B.M11 - 1;
            B.M24 = B.M22 - 1;

            // Product of three transforms
            return S * B * A;
        }
    }
}